﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;

namespace Hopscotch.Presentation.Common
{
    public abstract class ViewModelBase : PropertyNotificationObject, IErrorDataProvider
    {
        //Variables
        public string ViewTitle { get; protected set; }
        public Uri Icon16Uri { get; protected set; }

        private readonly Dictionary<string, List<DataErrorInfo>> validationErrors;

        //Events
        public event EventHandler<DataErrorsChangedEventArgs> ErrorsChanged;

        public ViewModelBase()
        {
            validationErrors = new Dictionary<string, List<DataErrorInfo>>();
        }

        public abstract void OnValidate();

        public virtual void Validate()
        {
            ClearErrors();

            OnValidate();

            if (HasErrors)
            {
                RaiseErrorsChanged(validationErrors.Keys);
            }
        }

        public void AddInfo(string key, string desc)
        {
            AddDataErrorInfo(key, new DataErrorInfo(ErrorType.Info, desc));
        }

        public void AddWarning(string key, string desc)
        {
            AddDataErrorInfo(key, new DataErrorInfo(ErrorType.Warning, desc));
        }

        public void AddError(string key, string desc)
        {
            AddDataErrorInfo(key, new DataErrorInfo(ErrorType.Error, desc));
        }

        public void AddDataErrorInfo(string key, DataErrorInfo dataErrorInfo)
        {
            if (!validationErrors.ContainsKey(key))
                validationErrors.Add(key, new List<DataErrorInfo>());

            int i = 0;
            while (i < validationErrors[key].Count)
            {
                var prev = validationErrors[key][i];
                if (dataErrorInfo.ErrorType > prev.ErrorType)
                {
                    break;
                }
                i++;
            }

            validationErrors[key].Insert(i, dataErrorInfo);
        }

        public List<DataErrorInfo> GetDataErrorInfoList(string propertyName)
        {
            if (!string.IsNullOrEmpty(propertyName) &&
                validationErrors.ContainsKey(propertyName))
            {
                return validationErrors[propertyName];
            }

            return null;
        }

        public IEnumerable GetErrors(string propertyName)
        {
            return GetDataErrorInfoList(propertyName);
        }

        public virtual bool HasErrors
        {
            get
            {
                return validationErrors.Count > 0;
            }
        }

        public void ClearErrors()
        {
            if (validationErrors.Count > 0)
            {
                var keys = validationErrors.Keys.ToList();
                validationErrors.Clear();

                RaiseErrorsChanged(keys);
            }
        }

        private void RaiseErrorsChanged(IEnumerable<string> keys)
        {
            foreach (string key in keys)
            {
                RaiseErrorsChanged(key);
            }
        }

        private void RaiseErrorsChanged(string key)
        {
            var errorsChanged = ErrorsChanged;

            if (errorsChanged != null)
            {
                errorsChanged(this, new DataErrorsChangedEventArgs(key));
            }
        }
    }
}
